一、程序生成模型
注意事项:把一个物体封装成一个类保存时,最好每个顶点只保存一次。然后用一个索引数组保存三角形的顶点索引。
二、外部载入OBJ格式模型
OBJ文件结构:
\# Blender v2.80 (sub 0) OBJ File: ''
\# ...
o Pyramid
v 1.000000 -1.000000 -1.000000
...
vt 0.5000000, 0.250000
...
vn 0.000000 -1.000000 0.000000
...
s off
f 2/1/1 3/2/1 4/3/1
...
注释:
o-物体名(忽略)
v-顶点
vt-纹理坐标
vn-法向量
s-是否平滑(忽略)
f-面
实现1:(不带索引)
class ModelImporter
{
private:
std::vector<float> vertVals;
std::vector<float> stVals;
std::vector<float> normVals;
std::vector<float> triangleVerts;
std::vector<float> textureCoords;
std::vector<float> normals;
public:
ModelImporter();
void parseOBJ(const char *filePath);
int getNumVertices();
std::vector<float> getVertices();
std::vector<float> getTextureCoordinates();
std::vector<float> getNormals();
};
class Mesh
{
protected:
int numVertices;
std::vector<glm::vec3> vertices;
std::vector<glm::vec2> texCoords;
std::vector<glm::vec3> normalVecs;
public:
Mesh();
Mesh(const char *filePath);
int getNumVertices();
std::vector<glm::vec3> getVertices();
std::vector<glm::vec2> getTextureCoords();
std::vector<glm::vec3> getNormals();
};
//---------------------------实现------------------------
//------------------------------------------------------
ModelImporter::ModelImporter() {}
void ModelImporter::parseOBJ(const char *filePath)
{
float x, y, z;
string content;
ifstream fileStream(filePath, ios::in);
string line = "";
while (!fileStream.eof())
{
getline(fileStream, line);
if (line.compare(0, 2, "v ") == 0)
{
stringstream ss(line.erase(0, 1));
ss >> x; ss >> y; ss >> z;
vertVals.push_back(x);
vertVals.push_back(y);
vertVals.push_back(z);
}
if (line.compare(0, 2, "vt") == 0)
{
stringstream ss(line.erase(0, 2));
ss >> x; ss >> y;
stVals.push_back(x);
stVals.push_back(y);
}
if (line.compare(0, 2, "vn") == 0)
{
stringstream ss(line.erase(0, 2));
ss >> x; ss >> y; ss >> z;
normVals.push_back(x);
normVals.push_back(y);
normVals.push_back(z);
}
if (line.compare(0, 2, "f ") == 0)
{
string oneCorner, v, t, n;
stringstream ss(line.erase(0, 2));
for (int i = 0; i < 3; i++)
{
getline(ss, oneCorner, ' ');
stringstream oneCornerSS(oneCorner);
getline(oneCornerSS, v, '/');
getline(oneCornerSS, t, '/');
getline(oneCornerSS, n, '/');
int vertRef = 0;
int tcRef = 0;
int normRef = 0;
if (v != "") vertRef = (stoi(v) - 1) * 3;
if (t != "") tcRef = (stoi(t) - 1) * 2;
if (n != "") normRef = (stoi(n) - 1) * 3;
triangleVerts.push_back(vertVals[vertRef]);
triangleVerts.push_back(vertVals[vertRef + 1]);
triangleVerts.push_back(vertVals[vertRef + 2]);
textureCoords.push_back(stVals[tcRef]);
textureCoords.push_back(stVals[tcRef + 1]);
normals.push_back(normVals[normRef]);
normals.push_back(normVals[normRef + 1]);
normals.push_back(normVals[normRef + 2]);
}
}
}
fileStream.close();
}
int ModelImporter::getNumVertices() { return (triangleVerts.size() / 3); }
std::vector<float> ModelImporter::getVertices() { return triangleVerts; }
std::vector<float> ModelImporter::getTextureCoordinates() { return textureCoords; }
std::vector<float> ModelImporter::getNormals() { return normals; }
//--------------------------------------------------------------
Mesh::Mesh() {}
Mesh::Mesh(const char *filePath)
{
ModelImporter modelImporter = ModelImporter();
modelImporter.parseOBJ(filePath);
numVertices = modelImporter.getNumVertices();
std::vector<float> verts = modelImporter.getVertices();
std::vector<float> tcs = modelImporter.getTextureCoordinates();
std::vector<float> normals = modelImporter.getNormals();
for (int i = 0; i < numVertices; i++)
{
vertices.push_back(glm::vec3(verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2]));
texCoords.push_back(glm::vec2(tcs[i * 2], tcs[i * 2 + 1]));
normalVecs.push_back(glm::vec3(normals[i * 3], normals[i * 3 + 1], normals[i * 3 + 2]));
}
}
int Mesh::getNumVertices() { return numVertices; }
std::vector<glm::vec3> Mesh::getVertices() { return vertices; }
std::vector<glm::vec2> Mesh::getTextureCoords() { return texCoords; }
std::vector<glm::vec3> Mesh::getNormals() { return normalVecs; }
实现2:(不带索引)
class IndicatedModelImporter
{
private:
std::vector<float> vertVals;
std::vector<float> stVals;
std::vector<float> normVals;
std::vector<float> triangleVerts;
std::vector<float> textureCoords;
std::vector<float> normals;
std::vector<int> inds;
public:
IndicatedModelImporter();
void parseOBJ(const char *filePath);
int getNumVertices();
std::vector<float> getVertices();
std::vector<float> getTextureCoordinates();
std::vector<float> getNormals();
std::vector<int> getInds();
};
class IndicatedMesh: public Mesh
{
protected:
//int numVertices;
//std::vector<glm::vec3> vertices;
//std::vector<glm::vec2> texCoords;
//std::vector<glm::vec3> normalVecs;
std::vector<int> inds;
public:
IndicatedMesh();
IndicatedMesh(const char *filePath);
int getNumVertices();
std::vector<glm::vec3> getVertices();
std::vector<glm::vec2> getTextureCoords();
std::vector<glm::vec3> getNormals();
std::vector<int> getIndicates();
int getNumIndicates();
};
//------------------------实现-----------------------------
//--------------------------------------------------------
IndicatedModelImporter::IndicatedModelImporter() { }
void IndicatedModelImporter::parseOBJ(const char *filePath)
{
float x, y, z;
string content;
ifstream fileStream(filePath, ios::in);
string line = "";
vector<ivec4> v_t_n;
while (!fileStream.eof())
{
getline(fileStream, line);
if (line.compare(0, 2, "v ") == 0)
{
stringstream ss(line.erase(0, 1));
ss >> x; ss >> y; ss >> z;
vertVals.push_back(x);
vertVals.push_back(y);
vertVals.push_back(z);
}
if (line.compare(0, 2, "vt") == 0)
{
stringstream ss(line.erase(0, 2));
ss >> x; ss >> y;
stVals.push_back(x);
stVals.push_back(y);
}
if (line.compare(0, 2, "vn") == 0)
{
stringstream ss(line.erase(0, 2));
ss >> x; ss >> y; ss >> z;
normVals.push_back(x);
normVals.push_back(y);
normVals.push_back(z);
}
if (line.compare(0, 2, "f ") == 0)
{
string oneCorner, v, t, n;
stringstream ss(line.erase(0, 2));
for (int i = 0; i < 3; i++)
{
getline(ss, oneCorner, ' ');
stringstream oneCornerSS(oneCorner);
getline(oneCornerSS, v, '/');
getline(oneCornerSS, t, '/');
getline(oneCornerSS, n, '/');
int vertInd = 0;
int tcInd = 0;
int normInd = 0;
if (v != "") vertInd = stoi(v);
if (t != "") tcInd = stoi(t);
if (n != "") normInd = stoi(n);
//判断
bool isExist = false;
int ind = 0;
for (size_t i = 0; i < v_t_n.size(); i++)
{
if (v_t_n[i].x != vertInd)
{
break;
}
if (v_t_n[i].y != tcInd)
{
break;
}
if (v_t_n[i].z == normInd)
{
isExist = true;
ind = v_t_n[i].w;
}
}
//根据判断结果
if (!isExist)
{
triangleVerts.push_back(vertVals[(vertInd -1) * 3]);
triangleVerts.push_back(vertVals[(vertInd - 1) * 3 + 1]);
triangleVerts.push_back(vertVals[(vertInd - 1) * 3 + 2]);
textureCoords.push_back(stVals[(tcInd - 1) * 2]);
textureCoords.push_back(stVals[(tcInd - 1) * 2 + 1]);
normals.push_back(normVals[(normInd - 1) * 3]);
normals.push_back(normVals[(normInd - 1) * 3 + 1]);
normals.push_back(normVals[(normInd - 1) * 3 + 2]);
int lastIndex = v_t_n.size() - 1;
v_t_n.push_back(ivec4(vertInd, tcInd, normInd, lastIndex + 1));
inds.push_back(lastIndex + 1);
}
else
{
inds.push_back(ind);
}
}
}
}
fileStream.close();
}
int IndicatedModelImporter::getNumVertices() { return (triangleVerts.size() / 3); }
std::vector<float> IndicatedModelImporter::getVertices() { return triangleVerts; }
std::vector<float> IndicatedModelImporter::getTextureCoordinates() { return textureCoords; }
std::vector<float> IndicatedModelImporter::getNormals() { return normals; }
std::vector<int> IndicatedModelImporter::getInds() { return inds; }
//--------------------------------------------------------
IndicatedMesh::IndicatedMesh() {}
IndicatedMesh::IndicatedMesh(const char *filePath)
{
IndicatedModelImporter modelImporter = IndicatedModelImporter();
modelImporter.parseOBJ(filePath);
numVertices = modelImporter.getNumVertices();
std::vector<float> verts = modelImporter.getVertices();
std::vector<float> tcs = modelImporter.getTextureCoordinates();
std::vector<float> normals = modelImporter.getNormals();
inds = modelImporter.getInds();
for (int i = 0; i < numVertices; i++)
{
vertices.push_back(glm::vec3(verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2]));
texCoords.push_back(glm::vec2(tcs[i * 2], tcs[i * 2 + 1]));
normalVecs.push_back(glm::vec3(normals[i * 3], normals[i * 3 + 1], normals[i * 3 + 2]));
}
}
int IndicatedMesh::getNumVertices() { return numVertices; }
std::vector<glm::vec3> IndicatedMesh::getVertices() { return vertices; }
std::vector<glm::vec2> IndicatedMesh::getTextureCoords() { return texCoords; }
std::vector<glm::vec3> IndicatedMesh::getNormals() { return normalVecs; }
std::vector<int> IndicatedMesh::getIndicates() { return inds; }
int IndicatedMesh::getNumIndicates() { return inds.size(); }